# This program analyses webfiles/* and generates a cpp library for ESP32 / ESP8266
# Each file is converted into PROGMEM data

from pathlib import Path
import mimetypes

cur_dir = Path(__file__).absolute().parent
search_dir = cur_dir / "webfiles"
items = list(search_dir.rglob("*"))
src = cur_dir.parts[-1]
if src == "src":
    src = cur_dir.parts[-2]
if src[-7:] == "-master":
    src = src[:(len(src)-len("-master"))]
master = src + "_webfiles"
cl = master + "_c"

print("\nAnalyzing dir", search_dir, "..." )
files = {}
content_types = {}
maxuri = 0
for item in items:
    if item.is_file():
        print("  ", item.relative_to(search_dir))
        
        key = str(item.relative_to(cur_dir)).replace("\\","/").replace("/","_").replace(" ","_").replace(".","_")
        
        files[key]= {}
        files[key]['name'] = item.name

        files[key]['suffix'] = item.suffix
        content_types[files[key]['suffix']] = {}
        content_types[files[key]['suffix']]['value'] = mimetypes.types_map[item.suffix]
        content_types[files[key]['suffix']]['name'] = master + "_content_type_" + item.suffix.replace(".", "") + "_P"

        files[key]['uri'] = "/" + str(item.relative_to(search_dir)).replace("\\","/")
        maxuri = max(maxuri, len(files[key]['uri']))

        f = open(item, "rb")
        content = f.read()
        f.close
        dumpHexa = ""
        size = 0
        for c in content:
            if size > 0:
                dumpHexa += ","
                if size % 12 == 0 :
                    dumpHexa += "\n"
            if size % 12 == 0:
                dumpHexa += " "
            dumpHexa += " 0x%02x" %c
            size += 1
    
        files[key]['size'] = size
        files[key]['cpp']  = "const char " + key + "_P[] PROGMEM =\n{\n" + dumpHexa + "\n};\n\n"
        files[key]['cpp'] += "void " + cl + "::send_" + key + "()\n{\n"
        files[key]['cpp'] += "  if (" + master + ".server != NULL)\n  {\n"
        files[key]['cpp'] += "    " + master + ".server->send_P(\n"
        files[key]['cpp'] += "      200,\n"
        files[key]['cpp'] += "      " + content_types[files[key]['suffix']]['name'] + ",\n"
        files[key]['cpp'] += "      " + key + "_P,\n"
        files[key]['cpp'] += "      " + str(size) + "\n    );\n  }\n}\n\n"


header = "//Generated by " + str(Path(__file__).name) + "\n\n"
header += "//" + str(len(files)) + " file(s) :\n"
favicon = False
for file in files:
    header += "//  " + files[file]['uri'] + "\n"
    header += "//     size : " + str(files[file]['size']) + " bytes\n"
    header += "//     content_type : " + content_types[files[file]['suffix']]['value'] + "\n"
    if file == "webfiles_favicon_ico" :
        favicon = True

header += "\n#ifndef " + master + "_h\n"
header += "#define " + master + "_h\n\n"
header += "#if defined(ESP32)\n"
header += "  #include <WebServer.h>\n"
header += "#elif defined(ESP8266)\n"
header += "  #include <ESP8266WebServer.h>\n"
header += "  #define WebServer ESP8266WebServer\n"
header += "#endif\n\n"

header += "class " + cl + "\n{\n"
header += "  public :\n    " + cl + "();\n\n"
header += "    void begin(WebServer &webServer);\n"
if favicon:
    header += "    void activateFavicon(); //must be specificly activated\n\n"
header += "    WebServer *server;\n\n"
header += "  private :\n"
for file in files:
    header += "    static void send_" + file + "();\n"
header += "};\n\nextern " + cl + " " + master + ";\n\n"
for file in files:
    header += "extern const char " + file + "_path_P[];\n"
header += "\n#endif\n\n"

master_h = master + ".h"
f = open(cur_dir / master_h, "w")
f.write(header)
f.close

cpp = "//Generated by " + str(Path(__file__).name) + "\n\n"
cpp += "#include \"" + master + ".h\"\n\n"
cpp += cl + " " + master + ";\n\n"

cpp += cl + "::" + cl + "()\n"
cpp += "{\n"
cpp += "  server = NULL;\n"
cpp += "}\n\n"

for file in files:
    cpp += "const char " + file + "_path_P[] PROGMEM = \"" + files[file]['uri'] + "\";\n"

cpp += '\n'
for content_type in content_types:
    cpp += "const char " + content_types[content_type]['name'] + "[] PROGMEM = \"" + content_types[content_type]['value'] + "\";\n"

cpp += "\nvoid " + cl + "::begin(WebServer &webServer)\n"
cpp += "{\n"
cpp += "  server = &webServer;\n\n"
cpp += "  char path[" + str(maxuri+1) + "];\n"
for file in files:
    if file != "webfiles_favicon_ico":
        cpp += "\n  strcpy_P(path, " + file + "_path_P);\n"
        cpp += "  server->on(path, send_" + file + ");\n"
cpp += "}\n\n"

if favicon:
    cpp += "void " + cl + "::activateFavicon()\n"
    cpp += "{\n"
    cpp += "  char path[" + str(maxuri+1) + "];\n"
    cpp += "  if (server != NULL)\n"
    cpp += "  {\n"
    cpp += "    strcpy_P(path, webfiles_favicon_ico_path_P);\n"
    cpp += "    server->on(path, send_webfiles_favicon_ico);\n"
    cpp += "  }\n"
    cpp += "}\n\n"

for file in files:
    cpp += files[file]['cpp']

master_cpp = master + ".cpp"
f = open(cur_dir / master_cpp, "w")
f.write(cpp)
f.close

print("\nGenerated files :")
print("  ", cur_dir / master_h)
print("  ", cur_dir / master_cpp)
input('Press ENTER to quit...')
